﻿/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2017 @ ShenZhen ,China
*******************************************************************************/
#ifndef __LOGGER_H__
#define __LOGGER_H__

#include "Mutex.h"
#include "Config.h"
#include "Tracer.h"
#include "SqliteWrapper.h"
#include "Utils.h"
#include "Thread.h"

#include <string>
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>

#include <iostream>
#include <vector>

typedef enum{
    LOG_ID_MAIN=0,
    LOG_ID_INVALID=-1
}LOG_ID_E;

#define USE_DELAY_LOGGER    1   /* 延迟日志,由LoggerFacade线程进行延迟写入日志,这样可以避免日志对主业务的影响 */

#if USE_DELAY_LOGGER
#define LOG_CORE(fmt,arg...)        do{LoggerFacade::getInstance()->coreLog(Utils::stringFormat("<@%s,%s,L%d>"fmt,\
                                       Utils::trimFilePath(__FILE__).c_str(),__FUNCTION__,__LINE__,##arg));\
                                       TRACE_NONE("<CoreLogger@%s,%s,L%d>"fmt,\
                                       Utils::trimFilePath(__FILE__).c_str(),__FUNCTION__,__LINE__,##arg);}while(0)
#define LOG_DATA(type,fmt,arg...)   do{LoggerFacade::getInstance()->dataLog(type,Utils::stringFormat(fmt,##arg));\
                                       TRACE_NONE("<DataLogger@%s,%s,L%d>"fmt"\n",\
                                       Utils::trimFilePath(__FILE__).c_str(),__FUNCTION__,__LINE__,##arg);}while(0)
#define LOG_MAIN(name,fmt,arg...)   do{LoggerFacade::getInstance()->mainLog(name,Utils::stringFormat("<@%s,%s,L%d>"fmt,\
                                       Utils::trimFilePath(__FILE__).c_str(),__FUNCTION__,__LINE__,##arg));}while(0)
#else
/* 核心日志,记录程序异常信息,写入速度一般 */
#define LOG_CORE(fmt,arg...)        do{CoreLogger::getInstance()->log("<@%s,%s,L%d>"fmt,\
                                       Utils::trimFilePath(__FILE__).c_str(),__FUNCTION__,__LINE__,##arg);\
                                       TRACE_NONE("<CoreLogger@%s,%s,L%d>"fmt,\
                                       Utils::trimFilePath(__FILE__).c_str(),__FUNCTION__,__LINE__,##arg);}while(0)
/* 数据库日志,记录重要数据,方便统计和查找,但由于写入速度较慢(每秒8条),不适合频繁记录 */
#define LOG_DATA(type,fmt,arg...)   do{DataLogger::getInstance()->log(type,fmt,##arg);\
                                       TRACE_NONE("<DataLogger@%s,%s,L%d>"fmt"\n",\
                                       Utils::trimFilePath(__FILE__).c_str(),__FUNCTION__,__LINE__,##arg);}while(0)
/* 用户日志,可用于记录用户数据,写入速度快,缺陷是不便于查看 */
#define LOG_MAIN(name,fmt,arg...)     do{MainLogger::getInstance()->log(name,"<@%s,%s,L%d>"fmt,\
                                         Utils::trimFilePath(__FILE__).c_str(),__FUNCTION__,__LINE__,##arg);}while(0)
#endif

/* Logger配置文件样例(Config文件):
 ----------------------------
 logger:
 {
    CoreLogger:
    {
        logPath="./corelog";  //日志根目录
        logName="core";       //日志名称(日志将放在corelog/core目录下)
        logFileNumMax=100;    //日志文件最大个数
    };
    DataLogger:
    {
        logPath="./datalog";
        logName="data";
    };
    MainLogger:
    {
        logPath="./mainlog";     //日志根目录
        logName="main";
        logStoreMax=1024;        //日志最大存储容量,单位为M
        logFileSizeMax=10;       //日志文件最大大小,单位为M
        monthDirEnable=1;        //日志按月份建立文件夹
        loglist=(                //子日志列表
        {name="sms";},
        {name="call";},
        );  
    };
 };
 ----------------------------
 */


typedef struct{
    std::string m_logName;
    std::string m_logPath;
    int m_logSize;
}LogInfo_S;
/**
 *  \file   Logger.h   
 *  \class  CoreLogger
 *  \brief  核心日志类(用来存储错误信息日志).
 */
class CoreLogger{
public:
    /**
     *  \brief  获取CoreLogger单例
     *  \param  void
     *  \return CoreLogger*
     *  \note   none
     */
    static CoreLogger* getInstance()
    {
        static CoreLogger instance;
        return &instance;
    };
    ~CoreLogger();
    bool initWithSettings(Settings settings);
    void log(const char * fmt, ...);
    std::vector<LogInfo_S> getLogInfoList();
private:
    CoreLogger();
    void initialize();
    void makeLog(const char * fmt,va_list argp);
    bool clearLog(int maxfiles);
private:
    std::string m_logPath;      /* log根目录 */
    std::string m_logName;      /* log名(log根目录下文件夹名称) */
    std::string m_logFileName;  /* log文件名 */
    int m_logFileNumMax;        /* 最大日志文件个数 */
    bool m_initialized; 
    unsigned int m_lineNum;
    FILE* m_logfp;
    MutexLock m_logLock;
};

/**
 *  \file   Logger.h   
 *  \class  DataLogger
 *  \brief  数据日志类(将日志存储在sqlite数据库中).
 *  \note   一般用于记录重要数据,方便统计和查找,但由于写入速度较慢(每秒8条),不适合频繁记录
 */
class DataLogger{
public:
    static DataLogger* getInstance()
    {
        static DataLogger instance;
        return &instance;
    }
    ~DataLogger();
    bool initWithSettings(Settings settings);
    void log(int logType,const char * fmt, ...);
    std::vector<LogInfo_S> getLogInfoList();
private:
    DataLogger();
    void initialize();
    void makeLog(int logType,const char * fmt,va_list argp);
    bool createLogDatabase(const std::string fileName);
private:
    MutexLock m_logLock;
    std::string m_logPath;
    std::string m_logName;
    std::string m_logDate;
    bool m_initialized;
    SqliteWrapper* m_dbHandler;
    std::string m_dbFileName;   /* 数据库文件全名 */
};

/**
 *  \file   Logger.h   
 *  \class  MainLogger
 *  \brief  主日志类(封装了log4z,用来存储用户日志).
 */
class MainLogger{
public:
    /**
     *  \brief  获取MainLogger单例
     *  \param  void
     *  \return MainLogger*
     *  \note   none
     */
    static MainLogger* getInstance()
    {
        static MainLogger instance;
        return &instance;
    };
    ~MainLogger();
    bool initWithSettings(Settings settings);
    void log(const std::string& name,const char * fmt, ...);
    std::vector<LogInfo_S> getLogInfoList();
private:
    MainLogger();
    void initialize(); 
    void makeLog(int logid, const char * fmt, va_list argp);
private:
    MutexLock m_logLock;
    typedef struct{
        int m_id;
        std::string m_name;
        std::string m_path;
    }Log4zLogInfo_S;
    std::vector<Log4zLogInfo_S> m_log4zLogInfos;
    std::string m_logPath;  /* log存储目录 */
    std::string m_logName;  /* 日志名 */
    int m_logFileSizeMax;   /* 最大单个日志文件大小,单位为兆字节(M) */
    int m_logStoreSizeMax;  /* 最大日志空间,单位为兆字节(M) */
    bool m_monthDirEnable;  /* 使能月份文件夹 */
    bool m_initialized;;
};

class LoggerFacade:public Runnable{
public:
    static LoggerFacade* getInstance()
    {
        static LoggerFacade instance;
        return &instance;
    }
    virtual ~LoggerFacade();
    void coreLog(const std::string& log);
    void dataLog(int type,const std::string& log);
    void mainLog(const std::string& name,const std::string& log);
private:
    LoggerFacade();
    virtual void run();
private:
	typedef enum
	{
        LOGGER_TYPE_CORE=0,
        LOGGER_TYPE_DATA,
        LOGGER_TYPE_MAIN
    }LOGGER_TYPE_E;
	typedef struct
	{
        int m_logger;
        int m_type;
        std::string m_name;
        std::string m_text;
    }LogContext_S;
    std::vector<LogContext_S> m_logVect;
    MutexLock m_logMutex;
    Thread m_mainThread;
};


#endif

